#pragma once
#include <iostream>
#include <pthread.h>
#include <functional>
#include "Protocol.hpp"
#include "Sock.hpp"

namespace tcpserver_ns
{
    class TcpServer;
    using func_t = std::function<protocol_ns::Response(const protocol_ns::Request&)>;

    class ThreadData
    {
    public:
        ThreadData(int sock, const std::string& ip, const uint16_t& port, TcpServer* tsvrp)
            :_sock(sock)
            ,_ip(ip)
            ,_port(port)
            ,_tsvrp(tsvrp)
        {}
        ~ThreadData()
        {}
    public:
        int _sock;
        std::string _ip;
        uint16_t _port;
        TcpServer* _tsvrp;
    };

    class TcpServer 
    {
    public:
        TcpServer(func_t func, const uint16_t& port) :_func(func), _port(port)
        {}
        void InitServer()
        {
            _listensock.Socket();
            _listensock.Bind(_port);
            _listensock.Listen();
            logMessage(INFO, "init server done, listensock:%d", _listensock);
        }
        void Start()
        {
            for ( ; ; )
            {
                std::string clientip;
                uint16_t clientport;
                int sock = _listensock.Accept(&clientip, &clientport);
                if (sock < 0) return;
                logMessage(DEBUG, "get a new client, client info : [%s:%d]", clientip.c_str(), clientport);

                pthread_t tid;
                ThreadData* td = new ThreadData(sock, clientip, clientport, this);
                pthread_create(&tid, nullptr, threadRoutine, td);
            }
        }
        static void* threadRoutine(void* args)
        {
            pthread_detach(pthread_self());
            ThreadData* td = static_cast<ThreadData*>(args);
            td->_tsvrp->ServiceIO(td->_sock, td->_ip, td->_port);
            delete td;
            return nullptr; 
        }
        void ServiceIO(int sock, const std::string& clientip, const uint16_t& clientport)
        {
            char buffer[1024];
            ssize_t s = recv(sock, buffer, sizeof(buffer), 0);

            protocol_ns::Request req;
            req.Deserialize(buffer);

            protocol_ns::Response resp = _func(req);

            std::string send_string;
            resp.Serialize(&send_string);
        }
        ~TcpServer()
        {}
    private:
        uint16_t _port;
        Sock _listensock;
        func_t _func;
    };
}